package info.batcloud.fanli.core.service.impl;

import info.batcloud.fanli.core.entity.FlashSaleItem;
import info.batcloud.fanli.core.enums.FlashSaleItemStatus;
import info.batcloud.fanli.core.operation.center.domain.Page;
import info.batcloud.fanli.core.repository.FlashSaleItemRepository;
import info.batcloud.fanli.core.service.FlashSaleRemindService;
import info.batcloud.fanli.core.service.MobilePushService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.*;
import java.util.concurrent.*;

@Service
public class FlashSaleRemindServiceImpl implements FlashSaleRemindService {

    @Inject
    private RedisTemplate redisTemplate;

    @Inject
    private FlashSaleItemRepository flashSaleItemRepository;

    public static final String FLASH_SALE_REMIND_QUEUE_KEY = "FLASH_SALE_REMIND_QUEUE";

    private Timer timer = new Timer(true);

    private ScheduledExecutorService scheduledExecutorService;

    private volatile long maxFlashSaleItemId = 0;

    @Inject
    private MobilePushService mobilePushService;

    private ThreadPoolExecutor threadPoolExecutor;

    @PostConstruct
    public void init() {
        threadPoolExecutor = new ThreadPoolExecutor(3, 100, 5, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
        scheduledExecutorService = Executors.newScheduledThreadPool(100);
    }

    @Override
    public void scheduleRemind() {
        Date now = new Date();
        List<FlashSaleItem> flashSaleItemList =
                flashSaleItemRepository.findByIdGreaterThanAndStartTimeGreaterThanAndStatusOrderByIdDesc(this.maxFlashSaleItemId, now, FlashSaleItemStatus.ONSALE);
        if (flashSaleItemList.size() > 0) {
            flashSaleItemList.forEach(fsi -> scheduleFlashSaleRemind(fsi, 30));
            flashSaleItemList.forEach(fsi -> scheduleFlashSaleRemind(fsi, 10));
            this.maxFlashSaleItemId = flashSaleItemList.get(flashSaleItemList.size() - 1).getId();
        }
    }

    private void scheduleFlashSaleRemind(FlashSaleItem fsi, int offsetMin) {
        long delay = fsi.getStartTime().getTime() - System.currentTimeMillis();
        if (delay < 0) {
            return;
        }
        long offsetMinMill =  offsetMin * 60 * 1000;
        if (delay < offsetMinMill) {
            return;
        }
        scheduledExecutorService.schedule(() -> doFlashSaleItemRemind(fsi), delay, TimeUnit.MILLISECONDS);
    }

    private void doFlashSaleItemRemind(FlashSaleItem fsi) {
        String key = getKey(fsi.getId());
        Set<Long> userIdList = redisTemplate.opsForSet().members(key);
        userIdList.forEach(userId -> {
            doFlashSaleItemRemind(fsi, userId);
        });
    }

    private void doFlashSaleItemRemind(FlashSaleItem fsi, long userId) {
        long remainSeconds = (fsi.getStartTime().getTime() - System.currentTimeMillis()) / (1000 * 60);
        mobilePushService.pushToAccount(userId + "", "", "您关注的免单商品【" + fsi.getItem().getTitle()+"】还有"+remainSeconds+"分钟就要开抢了，点击进行查看！",
                Page.FLASH_SALE, "");
    }

    @Override
    public void joinRemind(long flashSaleItemId, long userId) {
        String key = getKey(flashSaleItemId);
        redisTemplate.opsForSet().add(key, userId);
    }

    @Override
    public void exitRemind(long flashSaleItemId, long userId) {
        String key = getKey(flashSaleItemId);
        redisTemplate.opsForSet().remove(key, userId);
    }

    @Override
    public boolean checkRemind(long flashSaleItemId, long userId) {
        String key = getKey(flashSaleItemId);
        return redisTemplate.opsForSet().isMember(key, userId);
    }

    @Override
    public void doFlashSaleItemRemind(long flashSaleItemId) {
        FlashSaleItem fsi = flashSaleItemRepository.findOne(flashSaleItemId);
        this.doFlashSaleItemRemind(fsi);
    }

    @Override
    public void doFlashSaleItemUserRemind(long flashSaleItemId, long userId) {
        FlashSaleItem fsi = flashSaleItemRepository.findOne(flashSaleItemId);
        this.doFlashSaleItemRemind(fsi, userId);
    }

    private String getKey(long flashSaleItemId) {
        return FLASH_SALE_REMIND_QUEUE_KEY + ":" + flashSaleItemId;
    }
}
